package com.roadmap.common;

import java.io.FileInputStream;
import java.text.ParseException;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Random;

import org.apache.log4j.Logger;

import com.roadmap.common.BaseEnum.TaskDateScope;
import com.roadmap.common.BaseEnum.TimeType;
import com.roadmap.exception.NullObjectException;
import com.roadmap.util.chart.DateTimeUtility;

public class BaseUtility {	
	private static Random random;
	private final static Object lock = new Object();
	private static Properties props = loadProperties();
	private final static Logger logger = RdcLogger.getLogger(BaseUtility.class);

	/**
	 * convert a Data object to a String according to a specific format
	 */
	public static String formatDate(Date dt) {
		if (dt == null)
			return null;
		return BaseConst.DATE_FORMATE.format(dt);
	}

	public static String formatDateTime(Date dt) {
		if (dt == null)
			return null;
		return BaseConst.DATETIME_FORMAT.format(dt);
	}

	/** convert a string to a date */
	public static Date parseStringToDate(String str) {
		if (str == null)
			return null;
		Date date = null;
		try {
			date = BaseConst.DATE_FORMATE.parse(str);
		}
		catch (ParseException e) {
			e.printStackTrace();
		}
		return date;
	}
	
	/** convert a string to a date */
	public static Date parseStringToDateTime(String str) {
		if (str == null)
			return null;
		Date date = null;
		try {
			date = BaseConst.DATETIME_FORMAT.parse(str);
		}
		catch (ParseException e) {
			e.printStackTrace();
		}
		return date;
	}

	public static String getProperty(String propName) {
		if (propName == null)
			return null;
		
		synchronized (props) {
			return props.getProperty(propName);
		}
	}

	/** load properties from specific file */
	public static Properties loadProperties() {
		if (props != null)
			return props;

		synchronized (lock) {
			props = new Properties();
			try {
				// System.out.println(BaseConst.CONFIG_LOCATION);
				props.load(new FileInputStream(BaseConst.CONFIG_LOCATION
						+ BaseConst.RDC_PROPERTY_FILE));
			}
			catch (Exception e) {
				e.printStackTrace();
			}

			/* Finally, make sure System properties override file properties */
			Properties sysProps = System.getProperties();
			for (Iterator it = sysProps.entrySet().iterator(); it.hasNext();) {
				Map.Entry entry = (Map.Entry) it.next();
				if (props.containsKey(entry.getKey())) {
					props.put(entry.getKey(), entry.getValue());
				}
			}

			return props;
		}
	}

	private static Random getRandom() {
		synchronized (lock) {
			if (random == null) {
				long seed = System.currentTimeMillis();
				random = new Random(seed);
			}
			return random;
		}
	}

	/**
	 * this method generates a random string consisting 6 characters and each
	 * character in the string should be between char 'A' and 'Z'
	 */
	public static String getRandomString() {
		char min = 'A';
		char max = 'Z';
		int length = 6;

		// Unicode range of Basic Latin characters
		// see ASCII code: http://www.weste.net/tools/ASCII.asp
		// ensure the generated characters are all capital Latin letters 'A'-'Z'
		int range = max - min;
		// System.out.println(range);
		StringBuffer buff = new StringBuffer();

		for (int i = 0; i < length; ++i) {
			int n = getRandom().nextInt(range) + min;
			char c = (char) n;
			buff.append(c);
		}
		logger.debug("generate a random string: " + buff);

		return buff.toString();
	}

	/**
	 * compute the time diff between two dates
	 * 
	 * @param type:
	 *            if BaseUtility.TimeType.DAY chosen, return the days between
	 *            the two dates; if BaseUtility.TimeType.HOUR chosen, return the
	 *            hours between two dates
	 */
	public static int getTimeDiffBetween(Date big, Date small, TimeType type)
			throws NullObjectException {
		return DateTimeUtility.getTimeDiffBetween(big, small, type);
	}

	/**
	 * get the date before current day and the date after it
	 * 
	 * @return a array with two elements
	 */
	public static Date[] getFirstAndLastDayOfThreeDays(Date date)
			throws NullObjectException {
		return DateTimeUtility.getFirstAndLastDayOfThreeDays(date);
	}

	/**
	 * get the first date and last date of a week which the current day belongs
	 * to
	 * 
	 * @return a array with two elements
	 */
	public static Date[] getFirstAndLastDayOfWeek(Date date)
			throws NullObjectException {
		return DateTimeUtility.getFirstAndLastDayOfWeek(date);
	}

	/**
	 * get the first date and last date of a month which the current day belongs
	 * to
	 * 
	 * @return a array with two elements
	 */
	public static Date[] getFirstAndLastDayOfMonth(Date date)
			throws NullObjectException {
		return DateTimeUtility.getFirstAndLastDayOfMonth(date);
	}

	public static Date[] getFirstAndLastDayOfScope(Date date,
			TaskDateScope scope) throws NullObjectException {
		if (scope == TaskDateScope.THREE_DAYS)
			return DateTimeUtility.getFirstAndLastDayOfThreeDays(date);
		else if (scope == TaskDateScope.WEEK)
			return DateTimeUtility.getFirstAndLastDayOfWeek(date);
		else if (scope == TaskDateScope.MONTH)
			return DateTimeUtility.getFirstAndLastDayOfMonth(date);
		else
			return null;
	}

	/**
	 * something is scheduled to begin repeating from "start" to "end". Now a
	 * specific date scope is also given, find out the dates the object repeats
	 * in this scope.
	 * 
	 * @param first:
	 *            the first day of a given date scope
	 * @param last:
	 *            the last day of a given date scope
	 * @param start:
	 *            the day object begins to repeat
	 * @param end:
	 *            the day object stops to repeat
	 * @param cycle:
	 *            how many days the object repeats for each time
	 * @throws NullObjectException
	 */
	public static Date[] getDatesBetween(Date first, Date last, Date start,
			Date end, int cycle) throws NullObjectException {
		return DateTimeUtility.getDatesBetween(first, last, start, end, cycle);
	}

	public static String getProjectPath() {
		String proPath = System.getProperty("roadmap.home");
		return null;
	}
	
	 /** get a comparator which compares two date strings like "2009-02-12"*/
	public static java.util.Comparator<String> getDateStrComparator(){
		return new DateStrComparator();
		
	}
}

class DateStrComparator implements Comparator<String> {

	public int compare(String cur, String ret) {
		for (int i = 0; i < cur.length(); i++) {
			char c1 = cur.charAt(i);
			char c2 = ret.charAt(i);

			if (c1 > c2)
				return -1;
			else if (c1 < c2)
				return 1;
		}

		return 0;
	}

}
